﻿using System;
using System.Buffers.Text;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
using System.Web.ModelBinding;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Xml.Linq;
using DynamicData;
using Newtonsoft.Json;
using NodeNetwork.Toolkit.ContextMenu;
using NodeNetwork.Toolkit.Group.AddEndpointDropPanel;
using NodeNetwork.ViewModels;
using ReactiveUI;
using Splat;
using static WpfAppDemo.MainWindow;

namespace WpfAppDemo
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            //Create a new viewmodel for the NetworkView
            var network = new NetworkViewModel();

            /*
            //Create the node for the first node, set its name and add it to the network.
            var node1 = new NodeViewModel();
            node1.Name = "Node 1";
            network.Nodes.Add(node1);

            //Create the viewmodel for the input on the first node, set its name and add it to the node.
            var node1Input = new NodeInputViewModel();
            node1Input.Name = "Node 1 input";
            node1Input.PortPosition = PortPosition.Right;
            node1Input.MaxConnections = 2;
            node1.Inputs.Add(node1Input);

            var node1Output = new NodeOutputViewModel();
            node1Output.Name = "Node 1 output";
            node1.Outputs.Add(node1Output);

            //Create the second node viewmodel, set its name, add it to the network and add an output in a similar fashion.
            var node2 = new NodeViewModel();
            node2.Name = "Node 2";
            network.Nodes.Add(node2);

            var node2Input = new NodeInputViewModel();
            node2Input.Name = "Node 1 input";
            node2Input.PortPosition = PortPosition.Left;
            node2Input.MaxConnections = 3;
            node2.Inputs.Add(node2Input);

            var node2Output = new NodeOutputViewModel();
            node2Output.Name = "Node 2 output";
            node2.Outputs.Add(node2Output);

            var node3 = new NodeViewModel();
            node3.Name = "Node 3";
            network.Nodes.Add(node3);

            var node3Input = new NodeInputViewModel();
            node3Input.Name = "Node 3 input";
            node3.Inputs.Add(node3Input);

            var node3Input1 = new NodeInputViewModel();
            node3Input1.Name = "Node 3 input 1";
            node3.Inputs.Add(node3Input1);
            */
            ////Assign the viewmodel to the view.
            networkView.ViewModel = network;
        }

        private void ImportButton_Click(object sender, RoutedEventArgs e)
        {
            Microsoft.Win32.OpenFileDialog openFileDialog = new Microsoft.Win32.OpenFileDialog();
            openFileDialog.Filter = "JSON files (*.json)|*.json";
            if (openFileDialog.ShowDialog() == true)
            {
                var network = new NetworkViewModel();

                string json = File.ReadAllText(openFileDialog.FileName);
                SerializedNodeNetWork nodeNetwork = JsonConvert.DeserializeObject<SerializedNodeNetWork>(json);
                List<NodeInputViewModel> nodeInputs = new List<NodeInputViewModel>();
                List<NodeOutputViewModel> nodeOutputs = new List<NodeOutputViewModel>();
                foreach (var nodeVm in nodeNetwork.Nodes)
                {
                    var node = new NodeViewModel();
                    node.Name = nodeVm.Name;
                    node.HeaderIcon = nodeVm.HeaderIcon;
                    node.IsSelected = nodeVm.IsSelected;
                    node.IsCollapsed = nodeVm.IsCollapsed;
                    node.CanBeRemovedByUser = nodeVm.CanBeRemovedByUser;
                    node.Position = nodeVm.Position;
                    node.Resizable = nodeVm.Resizable;
                    network.Nodes.Add(node);

                    foreach (var input in nodeVm.Inputs)
                    {
                        var nodeInput = new NodeInputViewModel();
                        nodeInput.Name = input.Name;
                        nodeInput.MaxConnections = input.MaxConnections;
                        nodeInput.SortIndex = input.SortIndex;
                        nodeInput.Icon = input.Icon;
                        nodeInput.PortPosition = input.PortPosition;
                        nodeInput.Visibility = input.Visibility;
                        nodeInput.Group = input.Group;
                        nodeInput.Editor = input.Editor;
                        nodeInput.Port = new PortViewModel()
                        {
                            CenterPoint = input.Port.CenterPoint,
                            IsMirrored = input.Port.IsMirrored,
                            IsVisible = input.Port.IsVisible,
                            IsHighlighted = input.Port.IsHighlighted,
                            IsInErrorMode = input.Port.IsInErrorMode
                        };
                        node.Inputs.Add(nodeInput);
                        nodeInputs.Add(nodeInput);
                    }

                    foreach (var output in nodeVm.Outputs)
                    {
                        var nodeOutput = new NodeOutputViewModel();
                        nodeOutput.Name = output.Name;
                        nodeOutput.MaxConnections = output.MaxConnections;
                        nodeOutput.SortIndex = output.SortIndex;
                        nodeOutput.Icon = output.Icon;
                        nodeOutput.PortPosition = output.PortPosition;
                        nodeOutput.Visibility = output.Visibility;
                        nodeOutput.Group = output.Group;
                        nodeOutput.Editor = output.Editor;
                        nodeOutput.Port = new PortViewModel()
                        {
                            CenterPoint = output.Port.CenterPoint,
                            IsMirrored = output.Port.IsMirrored,
                            IsVisible = output.Port.IsVisible,
                            IsHighlighted = output.Port.IsHighlighted,
                            IsInErrorMode = output.Port.IsInErrorMode
                        };
                        node.Outputs.Add(nodeOutput);
                        nodeOutputs.Add(nodeOutput);
                    }
                }

                foreach (var connectionVm in nodeNetwork.Connections)
                {
                    var input = nodeInputs.FirstOrDefault(f=>StringToBase64(f.Port.CenterPoint.ToString()) == connectionVm.From);
                    var output = nodeOutputs.FirstOrDefault(f=>StringToBase64(f.Port.CenterPoint.ToString()) == connectionVm.To);
                    if (input == null || output == null)
                        continue;
                    var con = network.ConnectionFactory(input, output);
                    network.Connections.Edit(x => x.Add(con));
                }

                networkView.ViewModel = network;
            }
        }

        private void ExportButton_Click(object sender, RoutedEventArgs e)
        {
            Microsoft.Win32.SaveFileDialog saveFileDialog = new Microsoft.Win32.SaveFileDialog();
            saveFileDialog.Filter = "JSON files (*.json)|*.json";
            if (saveFileDialog.ShowDialog() == true)
            {
                if (networkView.ViewModel != null)
                {
                    var _vm = networkView.ViewModel;
                    List<SerializedNode> serializedNodes = new List<SerializedNode>();
                    foreach (NodeViewModel node in _vm.Nodes.Items)
                    {
                        List<SerializedInnerNode> inputs = new List<SerializedInnerNode>();
                        foreach (NodeInputViewModel input in node.Inputs.Items)
                        {
                            inputs.Add(new SerializedInnerNode
                            {
                                Name = input.Name,
                                MaxConnections = input.MaxConnections,
                                SortIndex = input.SortIndex,
                                Icon = input.Icon,
                                PortPosition = input.PortPosition,
                                Visibility = input.Visibility,
                                Group = input.Group,
                                Editor = input.Editor,
                                Port = new SerializedPort
                                {
                                    CenterPoint = input.Port.CenterPoint,
                                    IsMirrored = input.Port.IsMirrored,
                                    IsVisible = input.Port.IsVisible,
                                    IsHighlighted = input.Port.IsHighlighted,
                                    IsInErrorMode = input.Port.IsInErrorMode
                                }
                            });
                        }

                        List<SerializedInnerNode> outputs = new List<SerializedInnerNode>();
                        foreach (NodeOutputViewModel output in node.Outputs.Items)
                        {
                            outputs.Add(new SerializedInnerNode
                            {
                                Name = output.Name,
                                MaxConnections = output.MaxConnections,
                                SortIndex = output.SortIndex,
                                Icon = output.Icon,
                                PortPosition = output.PortPosition,
                                Visibility = output.Visibility,
                                Group = output.Group,
                                Editor = output.Editor,
                                Port = new SerializedPort
                                {
                                    CenterPoint = output.Port.CenterPoint,
                                    IsMirrored = output.Port.IsMirrored,
                                    IsVisible = output.Port.IsVisible,
                                    IsHighlighted = output.Port.IsHighlighted,
                                    IsInErrorMode = output.Port.IsInErrorMode
                                }
                            });
                        }

                        serializedNodes.Add(new SerializedNode
                        {
                            Name = node.Name,
                            HeaderIcon = node.HeaderIcon,
                            IsSelected = node.IsSelected,
                            IsCollapsed = node.IsCollapsed,
                            CanBeRemovedByUser = node.CanBeRemovedByUser,
                            Position = node.Position,
                            Resizable = node.Resizable,
                            Inputs = inputs,
                            Outputs = outputs
                        });
                    }

                    List<SerializedConnection> serializedConnections = new List<SerializedConnection>();
                    foreach (ConnectionViewModel connection in _vm.Connections.Items)
                    {
                        serializedConnections.Add(new SerializedConnection
                        {
                            From = StringToBase64(connection.Input.Port.CenterPoint.ToString()),
                            To = StringToBase64(connection.Output.Port.CenterPoint.ToString()),
                            InputName = connection.Input.Name,
                            OutputName = connection.Output.Name,
                            CanBeRemovedByUser = connection.CanBeRemovedByUser,
                            IsHighlighted = connection.IsHighlighted,
                            IsInErrorState = connection.IsInErrorState,
                            IsMarkedForDelete = connection.IsMarkedForDelete
                        });
                    }

                    SerializedNodeNetWork nodeNetWork = new SerializedNodeNetWork();
                    nodeNetWork.Nodes = serializedNodes;
                    nodeNetWork.Connections = serializedConnections;

                    string json = JsonConvert.SerializeObject(nodeNetWork);
                    File.WriteAllText(saveFileDialog.FileName, json);
                }
            }
        }

        private string StringToBase64(string originalString)
        {
            byte[] bytes = Encoding.UTF8.GetBytes(originalString);
            string base64String = Convert.ToBase64String(bytes);
            return base64String;
        }

        private string Base64ToString(string base64String)
        {
            byte[] bytes = Convert.FromBase64String(base64String);
            string originalString = Encoding.UTF8.GetString(bytes);
            return originalString;
        }

        public class SerializedNode
        {
            public string Name { get; set; }

            public IBitmap HeaderIcon { get; set; }

            public bool IsSelected { get; set; }

            public bool IsCollapsed { get; set; }

            public bool CanBeRemovedByUser { get; set; }

            public Point Position { get; set; }

            public ResizeOrientation Resizable { get; set; }

            public List<SerializedInnerNode> Inputs { get; set; }
            public List<SerializedInnerNode> Outputs { get; set; }
        }

        public class SerializedInnerNode
        {
            public string Name { get; set; }
            public int MaxConnections { get; set; }
            public int SortIndex { get; set; }
            public IBitmap Icon { get; set; }
            public PortPosition PortPosition { get; set; }
            public EndpointVisibility Visibility { get; set; }
            public EndpointGroup Group { get; set; }
            public NodeEndpointEditorViewModel Editor { get; set; }
            public SerializedPort Port { get; set; }
        }

        public class SerializedPort
        {
            public Point CenterPoint { get; set; }

            public bool IsMirrored { get; set; }

            public bool IsVisible { get; set; }

            public bool IsHighlighted { get; set; }

            public bool IsInErrorMode { get; set; }
        }

        public class SerializedConnection
        {
            public string From { get; set; }
            public string To { get; set; }
            public string InputName { get; set; }
            public string OutputName { get; set; }

            public bool CanBeRemovedByUser;

            public bool IsHighlighted;

            public bool IsInErrorState;

            public bool IsMarkedForDelete;
        }

        public class SerializedNodeNetWork
        {
            public List<SerializedNode> Nodes { get; set; }
            public List<SerializedConnection> Connections { get; set; }
        }
    }
}
